package com.alien.admin.context.task.impl;

import com.alien.admin.context.task.DeployMessageNotifier;
import com.alien.admin.context.task.DeployTaskManager;
import com.alien.admin.context.task.TaskQueue;
import com.alien.admin.context.task.handle.DeployJobHandler;
import com.alien.admin.context.task.handle.impl.JenkinsBuildImgJobHandler;
import com.alien.admin.context.task.handle.impl.JenkinsJobCheckHandler;
import com.alien.admin.context.task.handle.impl.K8SHealthCheckHandler;
import com.alien.admin.context.task.handle.impl.K8sDeployJobHandler;
import com.alien.admin.modules.container.service.K8sProjectService;
import com.alien.admin.modules.container.service.dto.K8sProjectQueryCriteria;
import com.alien.admin.modules.deploy.domain.DeployRec;
import com.alien.admin.modules.deploy.repository.DeployRecRepository;
import com.alien.admin.modules.publisher.service.PublishDeployService;
import com.alien.admin.utils.DeployConstant;
import com.alien.admin.utils.ValidationUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * @Description: 部署任务管理类
 * @Author: zsy
 * @Date: 2021/10/28 9:51
 */
@Slf4j
@Component
public class DeployTaskManagerImpl implements DeployTaskManager {
    @Autowired
    private TaskQueue taskQueue;
    @Autowired
    private DeployRecRepository deployRecRepository;

    @Autowired
    private K8sDeployJobHandler k8sDeployJobHandler;
    @Autowired
    private JenkinsBuildImgJobHandler jenkinsBuildImgJobHandler;
    @Autowired
    private JenkinsJobCheckHandler jenkinsJobCheckHandler;
    @Autowired
    private K8SHealthCheckHandler k8SHealthCheckHandler;
    @Autowired
    private PublishDeployService publishDeployService;
    @Autowired
    private K8sProjectService k8sProjectService;
    @Autowired
    private DeployMessageNotifier deployMessageNotifier;

    public void consumeTask() {
        try {
            Long recId = taskQueue.getTaskId();
            if (recId == null) {
                log.debug("queue is empty, sleep 10s");
                Thread.sleep(5000);
            } else {
                log.info("deploy record id :" + recId);
                DeployRec deployRec = deployRecRepository.findById(recId).orElseGet(DeployRec::new);
                ValidationUtil.isNull( deployRec.getId(),"DeployRec","id",recId);

                // 判断是否强制取消的任务
                if(taskQueue.isCancelTask(deployRec.getId())) {
                    cancelTask(deployRec);
                    return;
                }

                // 判断同一个服务是否有新的部署流程
                if (hasNewTask(deployRec)) {
                    // 同一个环境下，同一个项目有更新的任务，则取消当前任务
                    deployRec.setDeployStatus(DeployConstant.DEPLOY_STATUS_CANCEL);
                    deployRecRepository.save(deployRec);
                    return;
                }

                dispatch(deployRec);
                log.info("分发:record id :" + recId);

                /** 停顿一下，避免对jenkins和集群的访问频繁照成压力 */
                Thread.sleep(2000);
            }
        } catch (Exception e) {
            log.error("消费redis队列失败！", e);
        }
    }

    @Async
    public void dispatch(DeployRec deployRec) {
        DeployJobHandler deployJobHandler = getDeployJobHandler(deployRec);
        if(deployJobHandler != null) {
            try {
                deployJobHandler.process(deployRec);
            } catch (Exception e) {
            }
        }

        deployMessageNotifier.sendDeploymentStatusMessage(deployRec.getId());
        flowHandle(deployRec.getId());
    }

    /***
     * 判断任务是否在取消名单内，取消名单内，则会回滚部署
     */
    private void cancelTask(DeployRec deployRec) {
        Integer curDeployStatus = deployRec.getDeployStatus();
        // 防止重复设置
        if(!curDeployStatus.equals(DeployConstant.DEPLOY_STATUS_CANCEL)) {
            // 状态设置为取消
            deployRec.setDeployStatus(DeployConstant.DEPLOY_STATUS_CANCEL);
            deployRecRepository.save(deployRec);

            Integer stage = deployRec.getStage();
            if(DeployConstant.DEPLOY_STAGE_HEALTH_CHECK.equals(stage)) {
                // 服务回滚 to do
                String rollbackReplicaSetName = deployRec.getRollbackReplicaSetName();
                if(StringUtils.isNotEmpty(rollbackReplicaSetName)) {

                    K8sProjectQueryCriteria k8sProjectQueryCriteria = new K8sProjectQueryCriteria();
                    k8sProjectQueryCriteria.setEnv(deployRec.getEnv());
                    k8sProjectQueryCriteria.setProjectId(deployRec.getProjectId().longValue());
                    k8sProjectQueryCriteria.setRollbackReplicaSetName(rollbackReplicaSetName);
                    k8sProjectService.rollbackReplicaSet(k8sProjectQueryCriteria);
                }
            }
        }
    }

    /***
     * 关联流程的部署需要做额外处理
     * @param recId
     */
    private void flowHandle(Long recId) {
        DeployRec deployRec = deployRecRepository.findById(recId).orElseGet(DeployRec::new);
        ValidationUtil.isNull( deployRec.getId(),"DeployRec","id",recId);
        publishDeployService.process(deployRec);
    }

    boolean hasNewTask(DeployRec deployRec) {
        DeployRec deployRecInDb = deployRecRepository.findFirstByProjectIdAndEnvOrderByIdDesc(deployRec.getProjectId(), deployRec.getEnv());
        return !deployRecInDb.getId().equals(deployRec.getId());
    }

    private DeployJobHandler getDeployJobHandler(DeployRec deployRec) {
        Integer stage = deployRec.getStage();

        if(DeployConstant.DEPLOY_STAGE_BUILD_IMAGE_CHECK.equals(stage)) {
            return jenkinsJobCheckHandler;
        } else if(DeployConstant.DEPLOY_STAGE_HEALTH_CHECK.equals(stage)) {
            return k8SHealthCheckHandler;
        } else if(DeployConstant.DEPLOY_STAGE_BUILD_IMAGE.equals(stage)) {
            return jenkinsBuildImgJobHandler;
        } else if(DeployConstant.DEPLOY_STAGE_DEPLOY.equals(stage)) {
            return k8sDeployJobHandler;
        }
        return null;
    }
}
